package com.jfs.cmd.impl;

import cn.hutool.core.util.StrUtil;
import com.jfs.cmd.AbstractSIPCommander;
import com.jfs.cmd.SIPCommander;
import com.jfs.constant.SdpConstant;
import com.jfs.constant.SipConstant;
import com.jfs.entity.Device;
import com.jfs.enums.MessageEnum;
import com.jfs.enums.RtpEnum;
import com.jfs.envent.entity.MessageDeviceCmdEntity;
import com.jfs.envent.entity.MessageDeviceConfigEntity;
import com.jfs.properties.SipProperties;
import com.jfs.session.VideoStreamSessionManager;
import com.jfs.utils.XstreamUtil;
import com.jfs.zlk.entity.request.IsMediaOnline;
import com.jfs.zlk.entity.response.ResponseOpenRtpServer;
import com.jfs.zlk.provider.ZlkMediaServerAbilityProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.sip.*;
import javax.sip.address.SipURI;
import javax.sip.header.ViaHeader;
import javax.sip.message.Request;
import java.text.ParseException;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Description 指令实现类
 * @E-mail cwm3412638@163.com
 * @Author cwm
 * @Date 2022-08-23
 */
@Component
@Slf4j
public class SIPCommanderImpl extends AbstractSIPCommander implements SIPCommander {
    private final ZlkMediaServerAbilityProvider zlkMediaServerAbilityProvider;

    public SIPCommanderImpl(SipFactory sipFactory,
                            @Qualifier("tcpSipProvider") SipProvider tcpSipProvider,
                            @Qualifier("udpSipProvider") SipProvider udpSipProvider,
                            SipProperties sipProperties,
                            ZlkMediaServerAbilityProvider zlkMediaServerAbilityProvider) {
        super(sipFactory, tcpSipProvider, udpSipProvider, sipProperties);
        this.zlkMediaServerAbilityProvider = zlkMediaServerAbilityProvider;
    }

    /**
     * 查询设备
     *
     * @param requestEvent
     * @return
     * @throws InvalidArgumentException
     * @throws SipException
     * @throws ParseException
     */
    @Override
    public boolean deviceInfo(RequestEvent requestEvent) {
        try {
            String tm = Long.toString(System.currentTimeMillis());
            MessageDeviceCmdEntity messageDeviceCmdEntity = new MessageDeviceCmdEntity(MessageEnum.MESSAGE_DEVICE_INFO.getName(), getSN(), getDeviceIdFromRequest(requestEvent));
            String content = XstreamUtil.toXml(MessageDeviceCmdEntity.class, messageDeviceCmdEntity);
            //创建请求
            Request messageRequest = createMessageRequest(getDeviceIdFromRequest(requestEvent), content, getIpByRequest(requestEvent), getPortFromRequest(requestEvent), getTransactionFormRequest(requestEvent), null, "FromDev" + tm, null, getcallIdHeaderFromRequest(requestEvent));
            if (log.isDebugEnabled()) {
                log.debug("发送查询设备信息请求指令:{}", messageRequest);
            }
            //发送请求
            transmitRequest(getTransactionFormRequest(requestEvent), messageRequest);
        } catch (ParseException | InvalidArgumentException | SipException e) {
            log.error(e.getMessage());
            return false;
        }
        return true;
    }


    @Override
    public boolean catalog(RequestEvent requestEvent) {
        try {
            String tm = Long.toString(System.currentTimeMillis());
            MessageDeviceCmdEntity messageDeviceCmdEntity = new MessageDeviceCmdEntity(MessageEnum.MESSAGE_CATA_LOG.getName(), getSN(), getDeviceIdFromRequest(requestEvent));
            String content = XstreamUtil.toXml(MessageDeviceCmdEntity.class, messageDeviceCmdEntity);
            //创建请求
            Request messageRequest = createMessageRequest(getDeviceIdFromRequest(requestEvent), content, getIpByRequest(requestEvent), getPortFromRequest(requestEvent), getTransactionFormRequest(requestEvent), null, "FromDev" + tm, null, getcallIdHeaderFromRequest(requestEvent));
            if (log.isDebugEnabled()) {
                log.debug("发送查询设备目录请求指令:{}", messageRequest);
            }
            //发送请求
            transmitRequest(getTransactionFormRequest(requestEvent), messageRequest);
        } catch (ParseException | InvalidArgumentException | SipException e) {
            log.error(e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 请求预览视频流
     *
     * @param device
     * @param channelId
     * @return
     */
    @Override
    public String playStream(Device device, String channelId) {
        String streamId = VideoStreamSessionManager.getStreamId(channelId);
        String ssrc = null;
        if (StrUtil.isEmpty(streamId)){
            ssrc = VideoStreamSessionManager.createPlaySsrc();
           /* if (zlkMediaServerAbilityProvider.getRtpEnable()) {
                streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
            } else*/ {
                //转换成十六进制数据
                streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
            }
        }else {
            ssrc=VideoStreamSessionManager.getSsrc(streamId);
        }
        try {
            IsMediaOnline isMediaOnline = new IsMediaOnline();
            isMediaOnline.setStream(streamId);
            isMediaOnline.setSecret(zlkMediaServerAbilityProvider.getMeiaServerSecret());
            isMediaOnline.setApp(SipConstant.APP_ID);
            Boolean mediaOnline = zlkMediaServerAbilityProvider.isMediaOnline(isMediaOnline);
            //判断直播流是否在线 如果在线则不下发推流指令
            if (!mediaOnline){
                String streamMode = device.getStreamMode().toUpperCase();
                String mediaPort = null;
                // 使用动态udp端口
                if (zlkMediaServerAbilityProvider.getRtpEnable()) {
                    ResponseOpenRtpServer rtpServer = zlkMediaServerAbilityProvider.createRTPServer(streamId);
                    if (rtpServer.getCode() == 0) {
                        mediaPort = String.valueOf(rtpServer.getPort());
                        //打开端口成功需要移除集合中端口
                        zlkMediaServerAbilityProvider.removePortRange(rtpServer.getPort());
                    } else if (rtpServer.getCode() == -300) {
                        log.error("zlk流媒体打开流媒体rtp接收端口失败,错误消息:{}",rtpServer.getMsg());
                    } else if (rtpServer.getCode() == -400) {
                        log.error("zlk流媒体打开流媒体rtp接收端口失败,端口已经被占用,使用默认端口");
                        mediaPort = zlkMediaServerAbilityProvider.getRtpProxyPort();
                    }
                } else {
                    //使用默认端口
                    mediaPort = zlkMediaServerAbilityProvider.getRtpProxyPort();
                }
                if (Objects.isNull(mediaPort)){
                    //使用默认端口
                    mediaPort = zlkMediaServerAbilityProvider.getRtpProxyPort();
                }
                String sdpTemplate = null;
                if (zlkMediaServerAbilityProvider.getSdpEnable()) {
                    if (RtpEnum.UDP.getName().equals(streamMode)) {
                        sdpTemplate = SdpConstant.SDP_ENABLE_UDP;
                    } else if (RtpEnum.TCP_PASSIVE.getName().equals(streamMode)) {
                        sdpTemplate = SdpConstant.SDP_ENABLE_TCP_PASSIVE;
                    } else if (RtpEnum.TCP_ACTIVE.getName().equals(streamMode)) {
                        sdpTemplate = SdpConstant.SDP_ENABLE_TCP_ACTIVE;
                    }
                } else {
                    if (RtpEnum.UDP.getName().equals(streamMode)) {
                        sdpTemplate = SdpConstant.SDP_DISABLE_UDP;
                    } else if (RtpEnum.TCP_PASSIVE.getName().equals(streamMode)) {
                        sdpTemplate = SdpConstant.SDP_DISABLE_TCP_PASSIVE;
                    } else if (RtpEnum.TCP_ACTIVE.getName().equals(streamMode)) {
                        sdpTemplate = SdpConstant.SDP_DISABLE_TCP_ACTIVE;
                    }
                }
                sdpTemplate = replaceAll(SdpConstant.MEDIA_SERVER_IP, zlkMediaServerAbilityProvider.getMediaServerIp(), sdpTemplate);
                sdpTemplate = replaceAll(SdpConstant.SSRC, ssrc, sdpTemplate);
                sdpTemplate = replaceAll(SdpConstant.SIP_ID, sipProperties.getSipId(), sdpTemplate);
                sdpTemplate = replaceAll(SdpConstant.MEDIA_PORT, mediaPort, sdpTemplate);
                String tm = Long.toString(System.currentTimeMillis());
                Request inviteRequest = createInviteRequest(device.getIp(), sdpTemplate, channelId, device.getPort(), device.getTransport(), null, "FromInvite" + tm, null, getcallIdHeaderFromRequest(device.getTransport()), ssrc);
                if (log.isDebugEnabled()) {
                    log.debug("发送推流指令:{}", inviteRequest);
                }
                ClientTransaction clientTransaction = transmitRequest(device.getTransport(), inviteRequest);
                VideoStreamSessionManager.put(streamId, ssrc, clientTransaction, channelId,Integer.parseInt(mediaPort));
                //todo 添加通道 推流记录
                if (log.isDebugEnabled()) {
                    log.debug("下发设备推流指令成功,流播放id为:{},设备通道号为:{},ssrc码为:{}",streamId,channelId,ssrc);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            e.printStackTrace();
            return null;
        }
        return streamId;
    }

    @Override
    public boolean streamByeCmd(String streamId, String channelId) {
        try {
            ClientTransaction transaction = VideoStreamSessionManager.get(streamId);
            // 服务重启后
            if (transaction == null) {
                return false;
            }
            Dialog dialog = transaction.getDialog();
            if (dialog == null) {
                return false;
            }
            Request byeRequest = dialog.createRequest(Request.BYE);
            SipURI byeURI = (SipURI) byeRequest.getRequestURI();
            String vh = transaction.getRequest().getHeader(ViaHeader.NAME).toString();
            Pattern p = Pattern.compile("(\\d+\\.\\d+\\.\\d+\\.\\d+)\\:(\\d+)");
            Matcher matcher = p.matcher(vh);
            if (matcher.find()) {
                String ip = matcher.group(1);
                byeURI.setHost(ip);
                String port = matcher.group(2);
                byeURI.setPort(Integer.parseInt(port));
            }
            ViaHeader viaHeader = (ViaHeader) byeRequest.getHeader(ViaHeader.NAME);
            String protocol = viaHeader.getTransport().toUpperCase();
            ClientTransaction clientTransaction = getClientTransaction(protocol, byeRequest);
            dialog.sendRequest(clientTransaction);
            VideoStreamSessionManager.remove(streamId, channelId);
            //todo  关闭流媒体rtp接收端口
        } catch (Exception e) {
            log.error("关闭视频流发生异常:{}", e.getMessage());
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public boolean deviceStatus(RequestEvent requestEvent) {
        try {
            String tm = Long.toString(System.currentTimeMillis());
            MessageDeviceCmdEntity messageDeviceCmdEntity = new MessageDeviceCmdEntity(MessageEnum.MESSAGE_DEVICE_STATUS.getName(), getSN(), getDeviceIdFromRequest(requestEvent));
            String content = XstreamUtil.toXml(MessageDeviceCmdEntity.class, messageDeviceCmdEntity);
            //创建请求
            Request messageRequest = createMessageRequest(getDeviceIdFromRequest(requestEvent), content, getIpByRequest(requestEvent), getPortFromRequest(requestEvent), getTransactionFormRequest(requestEvent), null, "FromDev" + tm, null, getcallIdHeaderFromRequest(requestEvent));
            //发送请求
            transmitRequest(getTransactionFormRequest(requestEvent), messageRequest);
        } catch (ParseException | InvalidArgumentException | SipException e) {
            log.error(e.getMessage());
            return false;
        }
        return true;
    }

    @Override
    public boolean configDownload(RequestEvent requestEvent) {
        try {
            String tm = Long.toString(System.currentTimeMillis());
            MessageDeviceConfigEntity messageDeviceConfigEntity = new MessageDeviceConfigEntity(MessageEnum.MESSAGE_CONFIG_DOWNLOAD.getName(), getSN(), getDeviceIdFromRequest(requestEvent));
            messageDeviceConfigEntity.setConfigType("BasicParam");
            String content = XstreamUtil.toXml(MessageDeviceConfigEntity.class, messageDeviceConfigEntity);
            //创建请求
            Request messageRequest = createMessageRequest(getDeviceIdFromRequest(requestEvent), content, getIpByRequest(requestEvent), getPortFromRequest(requestEvent), getTransactionFormRequest(requestEvent), null, "FromDev" + tm, null, getcallIdHeaderFromRequest(requestEvent));
            //发送请求
            transmitRequest(getTransactionFormRequest(requestEvent), messageRequest);
        } catch (ParseException | InvalidArgumentException | SipException e) {
            log.error(e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * 获取sn码
     *
     * @return
     */
    public int getSN() {
        return (int) ((Math.random() * 9 + 1) * 100000);
    }

    /**
     * 拼装字符串方法
     *
     * @param target
     * @param replacement
     * @param source
     * @return
     */
    private static String replaceAll(String target, String replacement, String source) {
        if (target.contains("{")) {
            target = target.replace("{", "\\{");
        }
        if (target.contains("}")) {
            target = target.replace("}", "\\}");
        }
        Pattern p = Pattern.compile(target);
        Matcher m = p.matcher(source);
        return m.replaceAll(replacement);
    }
}
